﻿/*
 *
 * Simple example demonstrate a global interaction with two markers.
 * 
 * The  computation of the position of the local marker is evaluate
 * and a threshold above the distance from the global CS (marker A) 
 * will change the scale of the object. 
 * This demo is using the multimarker and the hiro marker
 * we put the threshold to be: 10cm on the right of the center, 
 * 10 cm front, and not more height than 4cm from the center.
 * the virtual sphere show the position where the user need to put 
 * the paddle
 * 
 * usage: osgARTpaddle.exe model_name1 size_model shift_x shift_y shift_z model_name2 size_model shift_x shift_y shift_z"<<std::endl;
 *
 * Copyright (c) 2005-2006
 * Julian Looser, Philip Lamb, Rapha�l Grasset, Hartmut Seichter.
 *
 */


#include <osg/Node>
#include <osg/Group>
#include <osg/Geode>
#include <osg/Projection>
#include <osg/AutoTransform>
#include <osg/ShapeDrawable>
#include <osg/Geometry>

#include <osgDB/ReadFile>


osg::Node* addARTModelTransform(osg::MatrixTransform* interactionTransform, char* name,float sizeModel,float shiftX, float shiftY, float heightMarker)
{

	// create a new node by reading in model from file
	osg::Node*	modelNode = osgDB::readNodeFile(name);

	//put model in origin
	osg::Matrix modelScale;
	osg::Matrix modelTranslate;
	osg::Matrix modelRot;
	
	osg::MatrixTransform*	unitTransform = new osg::MatrixTransform;
	osg::BoundingSphere bound=modelNode->getBound();

	modelScale.makeScale(sizeModel/bound.radius(),sizeModel/bound.radius(),sizeModel/bound.radius());
    modelRot.makeRotate(0.,osg::Vec3f(1.,0.,0.));
	modelTranslate.makeTranslate(-bound.center());

	unitTransform->postMult(modelTranslate);
	unitTransform->postMult(modelRot);
	unitTransform->postMult(modelScale);

	unitTransform->addChild(modelNode);

	//put model on the marker (not on the middle)
	osg::MatrixTransform*	trackerCenterTransform = new osg::MatrixTransform;

	osg::Matrix artCenter;
	artCenter.makeTranslate(shiftX,shiftY,heightMarker);
	trackerCenterTransform->postMult(artCenter);

	trackerCenterTransform->addChild(unitTransform);

	osg::MatrixTransform* myObject=new osg::MatrixTransform;
	
	interactionTransform->addChild(trackerCenterTransform);
	myObject->addChild(interactionTransform);

	return myObject;
}

void updateInteraction(osg::MatrixTransform& paddleTrans,osg::MatrixTransform& interactionTransfo)
{
	//get the relative position of marker2
	osg::Vec3f local_pos=paddleTrans.getMatrix().getTrans();

	std::cerr<<"local position="<<local_pos[0]<<" "<<local_pos[1]<<" "<<local_pos[2]<<std::endl;

	//if the paddle marker (marker 2) is at a specific distance from the global CS (marker 1)
	if ((local_pos[0]>100)&&(local_pos[1]<-100)&&(local_pos[2]<30))
	{
		//we change the scale of the object on marker 1
			interactionTransfo.setMatrix(osg::Matrix::scale(2.,2.,2.));
	}
	else
	{
		//otherwise default scale
			interactionTransfo.setMatrix(osg::Matrix::scale(1.,1.,1.));
	}

}

int main(int argc, char* argv[]) {

	if (argc<11)
	{
		std::cout<<"osgartsimple model_name1 size_model shift_x shift_y shift_z model_name2 size_model shift_x shift_y shift_z"<<std::endl;
		exit(-1);
	}
	osg::setNotifyLevel(osg::ALWAYS);

	osgARTInit(&argc, argv);
	
	osgProducer::Viewer viewer;
	viewer.setUpViewer(osgProducer::Viewer::ESCAPE_SETS_DONE);
	viewer.getCullSettings().setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);

#ifndef __linux
	// somehow on Ubuntu Dapper this ends up in a segmentation fault
	viewer.getCamera(0)->getRenderSurface()->fullScreen(false);
#endif


	// load a video plugin
	osg::ref_ptr<osgART::GenericVideo> video = 
	osgART::VideoManager::createVideoFromPlugin("osgart_artoolkit");

	/* open the video */
	video->open();

	/* load a tracker plugin */
	osg::ref_ptr<osgART::GenericTracker> tracker = 
		osgART::TrackerManager::createTrackerFromPlugin("osgart_artoolkit_tracker");

	tracker->init(video->getWidth(), video->getHeight(),"data/markers_listpaddle.dat");

	//Adding video background
	osg::Group* foregroundGroup	= new osg::Group();

	osgART::VideoBackground* videoBackground=new osgART::VideoBackground(video.get());

	videoBackground->setTextureMode(osgART::GenericVideoObject::USE_TEXTURE_RECTANGLE);

	videoBackground->init();
	
	foregroundGroup->addChild(videoBackground);

	foregroundGroup->getOrCreateStateSet()->setRenderBinDetails(2, "RenderBin");

	osg::Projection* projectionMatrix = new osg::Projection(osg::Matrix(tracker->getProjectionMatrix()));
	
	// create marker with id number '0'
	osg::ref_ptr<osgART::Marker> marker = tracker->getMarker(0);
		
	// check before accessing the linked marker
	if (!marker.valid()) {
        
		osg::notify(osg::FATAL) << "No Marker defined!" << std::endl;

		exit(-1);
	}

	// activate the marker
	marker->setActive(true);

	// create a matrix transform related to the marker
	osg::ref_ptr<osg::MatrixTransform> markerTrans = 
		new osgART::ARTTransform(marker.get());

	//create an interaction transformation node (where we will apply the modification of the object)
	osg::MatrixTransform* interactionTransfo = new osg::MatrixTransform();

	//adding the model to the scenegraph
	markerTrans->addChild(addARTModelTransform(interactionTransfo,argv[1],atof(argv[2]),atof(argv[3]),atof(argv[4]),atof(argv[5])));

	//adding a sphere for the point of interaction

	osg::MatrixTransform* indicatorTransfo = new osg::MatrixTransform(osg::Matrix::translate(100.,-100.,25.));

	float sphereSize = 10.0f;
	osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.,0.,0.), sphereSize));
	sd->setColor(osg::Vec4(1, 0, 0, 1));
	
	osg::Geode* geode = new osg::Geode();
	geode->addDrawable(sd);

	indicatorTransfo->addChild(geode);
	markerTrans->addChild(indicatorTransfo);
	//adding a local marker

	//activate the marker
	osg::ref_ptr<osgART::Marker> marker2 = tracker->getMarker(1);

		// check before accessing the linked marker
	if (!marker2.valid()) {
        
		osg::notify(osg::FATAL) << "No Marker defined!" << std::endl;

		exit(-1);
	}

	marker2->setActive(true);

	//create a normal matrix transformation
	osg::MatrixTransform* paddleTrans = new osg::MatrixTransform();

	//put a local transformation
	paddleTrans->setUpdateCallback(new osgART::ARLocalTransformCallback(marker.get(),marker2.get()));

	//create an interaction transformation node (where we will apply the modification of the object)
	osg::MatrixTransform* interactionTransfo2 = new osg::MatrixTransform();

	paddleTrans->addChild(addARTModelTransform(interactionTransfo2,argv[6],atof(argv[7]),atof(argv[8]),atof(argv[9]),atof(argv[10])));

	//and after add to the markerTrans (global reference)
	markerTrans->addChild(paddleTrans);

	osg::Group* sceneGroup = new osg::Group();
	sceneGroup->getOrCreateStateSet()->setRenderBinDetails(5, "RenderBin");
	sceneGroup->addChild(markerTrans.get());
	foregroundGroup->addChild(sceneGroup);
	
	osg::MatrixTransform* modelViewMatrix = new osg::MatrixTransform();
	modelViewMatrix->addChild(foregroundGroup);
	projectionMatrix->addChild(modelViewMatrix);
	
	osg::Group* root = new osg::Group();
	root->addChild(projectionMatrix);

	viewer.setSceneData(root);

	viewer.realize();
	
	video->start();
	
    while (!viewer.done()) {
		
		viewer.sync();	
		
		video->update();

		tracker->setImage(video.get());
		tracker->update();
		
		//update with the last local transformation and the transformation nodes 
		//where we can apply the modification of the object
		updateInteraction(*paddleTrans,*interactionTransfo);

        viewer.update();
        viewer.frame();
	
    }
    
	viewer.sync();
    viewer.cleanup_frame();
    viewer.sync();

	video->stop();
	video->close();
	
}
